home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume4 / se / part3 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  50.5 KB

  1. From: Jeff Lee <talcott!seismo!gatech!jeff>
  2. Subject: Georgia Tech 'se' screen editor (Part 3 of 8)
  3. Keywords: Software Tools, Yet Another Screen Editor, Both BSD and USG
  4. Newsgroups: mod.sources
  5. Approved: jpn@panda.UUCP
  6.  
  7. Mod.sources:  Volume 4, Issue 84
  8. Submitted by: Jeff Lee <seismo!gatech!jeff>
  9.  
  10. #! /bin/sh
  11. # This is a shell archive, meaning:
  12. # 1. Remove everything above the #! /bin/sh line.
  13. # 2. Save the resulting text in a file.
  14. # 3. Execute the file with /bin/sh (not csh) to create:
  15. #    docmd1.c
  16. #    docmd2.c
  17. #    misc.c
  18. # This archive created: Tue Apr 29 11:01:33 1986
  19. export PATH; PATH=/bin:/usr/bin:$PATH
  20. echo shar: "extracting 'docmd1.c'" '(29123 characters)'
  21. if test -f 'docmd1.c'
  22. then
  23.     echo shar: "will not over-write existing file 'docmd1.c'"
  24. else
  25. cat << \SHAR_EOF > 'docmd1.c'
  26. /*
  27. ** docmd1.c
  28. **
  29. ** main command processor.  routines for individual commands
  30. */
  31.  
  32. #include "se.h"
  33. #include "extern.h"
  34.  
  35. /* static data definitions -- variables only needed in this file */
  36. static char Tlpat[MAXPAT] = "";    /* saved character list for y/t command */
  37. static char Tabstr[MAXLINE] = "";    /* string representation of tab stops */
  38. static char Ddir = FORWARD;        /* delete direction */
  39. static int Compress;            /* compress/expand tabs on read/write */
  40.  
  41. /* docmd --- handle all commands except globals */
  42.  
  43. int docmd (lin, i, glob, status)
  44. char lin[];
  45. int i, glob, *status;
  46. {
  47.     char file[MAXLINE], sub[MAXPAT];
  48.     char kname;
  49.     int gflag, line3, pflag, flag, fflag, junk, allbut, tflag;
  50.     int append (), ckchar (), ckp (), ckupd (), copy ();
  51.     int delete (), domark (), doopt (), doprnt (), doread ();
  52.     int doshell ();
  53.     int dotlit (), doundo (), dowrit (), getfn (), getkn ();
  54.     int getone (), getrange (), getrhs (), getstr (), inject ();
  55.     int join (), makset (), move (), nextln (), optpat ();
  56.     int prevln (), substr (), draw_box ();
  57.     char *expand_env ();
  58.  
  59.  
  60.     *status = ERR;
  61.     if (intrpt ())  /* catch a pending interrupt */
  62.         return (*status);
  63.  
  64.     switch (lin[i]) {
  65.     case APPENDCOM:
  66.     case UCAPPENDCOM:
  67.         if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  68.         {
  69.             defalt (Curln, Curln);
  70.             if (lin[i + 1] == '\n')
  71.             {
  72.                 /* avoid updating with inline insertion */
  73.                 adjust_window (Line1, Line2);
  74.                 updscreen ();
  75.             }
  76.             *status = append (Line2, &lin[i + 1]);
  77.         }
  78.         break;
  79.  
  80.     case PRINTCUR:
  81.         if (lin[i + 1] == '\n')
  82.         {
  83.             defalt (Curln, Curln);
  84.             saynum (Line2);
  85.             *status = OK;
  86.         }
  87.         break;
  88.  
  89.     case OVERLAYCOM:
  90.     case UCOVERLAYCOM:
  91.         defalt (Curln, Curln);
  92.         if (lin[i + 1] == '\n')
  93.             overlay (status);
  94.         break;
  95.  
  96.     case CHANGE:
  97.     case UCCHANGE:
  98.         defalt (Curln, Curln);
  99.         if (Line1 <= 0)
  100.             Errcode = EORANGE;
  101.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  102.         {
  103.             if (lin[i + 1] == '\n')
  104.             {
  105.                 /* avoid updating with inline insertion */
  106.                 adjust_window (Line2, Line2);
  107.                 updscreen ();
  108.             }
  109.             First_affected = min (First_affected, Line1);
  110.             if (lin[i + 1] == '\n')
  111.                 warn_deleted (Line1, Line2);
  112.             *status = append (Line2, &lin[i + 1]);
  113.             if (*status != ERR)
  114.             {
  115.                 line3 = Curln;
  116.                 delete (Line1, Line2, status);
  117.                 Curln = line3 - (Line2 - Line1 + 1);
  118.                 /* adjust for deleted lines */
  119.             }
  120.         }
  121.         break;
  122.  
  123.     case DELCOM:
  124.     case UCDELCOM:
  125.         if (ckp (lin, i + 1, &pflag, status) == OK)
  126.         {
  127.             defalt (Curln, Curln);
  128.             if (delete (Line1, Line2, status) == OK
  129.                 && Ddir == FORWARD
  130.                 && nextln (Curln) != 0)
  131.                 Curln = nextln (Curln);
  132.         }
  133.         break;
  134.  
  135.     case INSERT:
  136.     case UCINSERT:
  137.         defalt (Curln, Curln);
  138.         if (Line1 <= 0)
  139.             Errcode = EORANGE;
  140.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  141.         {
  142.             if (lin[i + 1] == '\n')
  143.             {
  144.                 /* avoid updating with inline insertion */
  145.                 adjust_window (Line1, Line2);
  146.                 updscreen ();
  147.             }
  148.             *status = append (prevln (Line2), &lin[i + 1]);
  149.         }
  150.         break;
  151.  
  152.     case MOVECOM:
  153.     case UCMOVECOM:
  154.         i++;
  155.         if (getone (lin, &i, &line3, status) == EOF)
  156.             *status = ERR;
  157.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  158.         {
  159.             defalt (Curln, Curln);
  160.             *status = move (line3);
  161.         }
  162.         break;
  163.  
  164.     case COPYCOM:
  165.     case UCCOPYCOM:
  166.         if (! Unix_mode)
  167.             goto translit;    /* SWT uses 't' for translit */
  168.         /* else
  169.             fall through and act normally */
  170.     docopy:
  171.         i++;
  172.         if (getone (lin, &i, &line3, status) == EOF)
  173.             *status = ERR;
  174.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  175.         {
  176.             defalt (Curln, Curln);
  177.             *status = copy (line3);
  178.         }
  179.         break;
  180.  
  181.     case SUBSTITUTE:
  182.     case UCSUBSTITUTE:
  183.         i++;
  184.         if (lin[i] == '\n')
  185.         {
  186.             /* turn "s\n" into "s//%/\n" */
  187.             lin[i+0] = '/';
  188.             lin[i+1] = '/';
  189.             lin[i+2] = Unix_mode ? '%' : '&';
  190.             lin[i+3] = '/';
  191.             lin[i+4] = '\n';
  192.             lin[i+5] = EOS;
  193.             Peekc = SKIP_RIGHT;
  194.         }
  195.         else
  196.         {
  197.             /* try to handle "s/stuff\n" */
  198.             int j, missing_delim;
  199.  
  200.             missing_delim = YES;
  201.             for (j = i + 1; lin[j] != '\n'; j++)
  202.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  203.                     j++;    /* skip esc, loop continues */
  204.                 else if (lin[j] == lin[i])
  205.                 {
  206.                     missing_delim = NO;
  207.                     break;    /* for */
  208.                 }
  209.  
  210.             if (missing_delim)
  211.             {
  212.                 for (; lin[j] != EOS; j++)
  213.                     ;
  214.                 j--;        /* j now at newline */
  215.  
  216.                 lin[j] = lin[i];    /* delim */
  217.                 lin[++j] = '\n';
  218.                 lin[++j] = EOS;
  219.                 Peekc = SKIP_RIGHT;
  220.                 /* rest of routines will continue to fix up */
  221.             }
  222.         }
  223.  
  224.         if (optpat (lin, &i) == OK
  225.             && getrhs (lin, &i, sub, &gflag) == OK
  226.             && ckp (lin, i + 1, &pflag, status) == OK)
  227.         {
  228.             defalt (Curln, Curln);
  229.             *status = subst (sub, gflag, glob);
  230.         }
  231.         break;
  232.  
  233.     case TLITCOM:
  234.     case UCTLITCOM:
  235.         if (! Unix_mode)
  236.             goto docopy;    /* SWT uses 'y' for copying */
  237.         /* else
  238.             fall through and act normally */
  239.     translit:
  240.         i++;
  241.         if (lin[i] == '\n')
  242.         {
  243.             /* turn "y\n" into "y//%/\n" */
  244.             lin[i+0] = '/';
  245.             lin[i+1] = '/';
  246.             lin[i+2] = Unix_mode ? '%' : '&';
  247.             lin[i+3] = '/';
  248.             lin[i+4] = '\n';
  249.             lin[i+5] = EOS;
  250.             Peekc = SKIP_RIGHT;
  251.         }
  252.         else
  253.         {
  254.             /* try to handle "y/stuff\n" */
  255.             int j, missing_delim;
  256.  
  257.             missing_delim = YES;
  258.             for (j = i + 1; lin[j] != '\n'; j++)
  259.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  260.                     j++;    /* skip esc, loop continues */
  261.                 else if (lin[j] == lin[i])
  262.                 {
  263.                     missing_delim = NO;
  264.                     break;    /* for */
  265.                 }
  266.  
  267.             if (missing_delim)
  268.             {
  269.                 for (; lin[j] != EOS; j++)
  270.                     ;
  271.                 j--;        /* j now at newline */
  272.  
  273.                 lin[j] = lin[i];    /* delim */
  274.                 lin[++j] = '\n';
  275.                 lin[++j] = EOS;
  276.                 Peekc = SKIP_RIGHT;
  277.                 /* rest of routines will continue to fix up */
  278.             }
  279.         }
  280.  
  281.         if (getrange (lin, &i, Tlpat, MAXPAT, &allbut) == OK
  282.             && makset (lin, &i, sub, MAXPAT) == OK
  283.             && ckp (lin, i + 1, &pflag, status) == OK)
  284.         {
  285.             defalt (Curln, Curln);
  286.             *status = dotlit (sub, allbut);
  287.         }
  288.         break;
  289.  
  290.     case JOINCOM:
  291.     case UCJOINCOM:
  292.         i++;
  293.         if (getstr (lin, &i, sub, MAXPAT) == OK
  294.             && ckp (lin, i + 1, &pflag, status) == OK)
  295.         {
  296.             defalt (prevln (Curln), Curln);
  297.             *status = join (sub);
  298.         }
  299.         break;
  300.  
  301.     case UNDOCOM:
  302.     case UCUNDOCOM:
  303.         i++;
  304.         defalt (Curln, Curln);
  305.         if (ckchar (UCDELCOM, DELCOM, lin, &i, &flag, status) == OK
  306.             && ckp (lin, i, &pflag, status) == OK)
  307.             *status = doundo (flag, status);
  308.         break;
  309.  
  310.     case ENTER:
  311.     case UCENTER:
  312.         i++;
  313.         if (Nlines != 0)
  314.             Errcode = EBADLNR;
  315.         else if (ckupd (lin, &i, ENTER, status) == OK
  316.             && ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  317.             if (getfn (lin, i - 1, file) == OK)
  318.             {
  319.                 strcpy (Savfil, expand_env (file));
  320.                 mesg (Savfil, FILE_MSG);
  321.                 clrbuf ();
  322.                 mkbuf ();
  323.                 dfltsopt (file);
  324.                 *status = doread (0, file, tflag);
  325.                 First_affected = 0;
  326.                 Curln = min (1, Lastln);
  327.                 Buffer_changed = NO;
  328.             }
  329.             else
  330.                 *status = ERR;
  331.         break;
  332.  
  333.     case PRINTFIL:
  334.     case UCPRINTFIL:
  335.         if (Nlines != 0)
  336.             Errcode = EBADLNR;
  337.         else if (getfn (lin, i, file) == OK)
  338.         {
  339.             strcpy (Savfil, expand_env (file));
  340.             mesg (Savfil, FILE_MSG);
  341.             *status = OK;
  342.         }
  343.         break;
  344.  
  345.     case READCOM:
  346.     case UCREADCOM:
  347.         i++;
  348.         if (ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  349.             if (getfn (lin, i - 1, file) == OK)
  350.             {
  351.                 defalt (Curln, Curln);
  352.                 *status = doread (Line2, file, tflag);
  353.             }
  354.         break;
  355.  
  356.     case WRITECOM:
  357.     case UCWRITECOM:
  358.         i++;
  359.         flag = NO;
  360.         fflag = NO;
  361.         junk = ckchar ('>', '+', lin, &i, &flag, &junk);
  362.         if (flag == NO)
  363.             junk = ckchar ('!', '!', lin, &i, &fflag, &junk);
  364.         junk = ckchar ('x', 'X', lin, &i, &tflag, &junk);
  365.         if (getfn (lin, i - 1, file) == OK)
  366.         {
  367.             defalt (1, Lastln);
  368.             *status = dowrit (Line1, Line2, file, flag, fflag, tflag);
  369.         }
  370.         break;
  371.  
  372.     case PRINT:
  373.     case UCPRINT:
  374.         if (lin[i + 1] == '\n')
  375.         {
  376.             defalt (1, Topln);
  377.             *status = doprnt (Line1, Line2);
  378.         }
  379.         break;
  380.  
  381.     case PAGECOM:
  382.         defalt (1, min (Lastln, Botrow - Toprow + Topln));
  383.         if (Line1 <= 0)
  384.             Errcode = EORANGE;
  385.         else if (lin[i + 1] == '\n')
  386.         {
  387.             Topln = Line2;
  388.             Curln = Line2;
  389.             First_affected = Line2;
  390.             *status = OK;
  391.         }
  392.         break;
  393.  
  394.     case NAMECOM:
  395.     case UCNAMECOM:
  396.         i++;
  397.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  398.             && lin[i] == '\n')
  399.             uniquely_name (kname, status);
  400.         break;
  401.  
  402.     case MARKCOM:
  403.     case UCMARKCOM:
  404.         i++;
  405.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  406.             && lin[i] == '\n')
  407.         {
  408.             defalt (Curln, Curln);
  409.             *status = domark (kname);
  410.         }
  411.         break;
  412.  
  413.     case '\n':
  414.         line3 = nextln (Curln);
  415.         defalt (line3, line3);
  416.         *status = doprnt (Line2, Line2);
  417.         break;
  418.  
  419.     case LOCATECMD:
  420.     case UCLOCATECMD:
  421.         if (lin[i+1] == '\n')
  422.         {
  423.             char *sysname ();
  424.  
  425.             remark (sysname ());
  426.             *status = OK;
  427.         }
  428.         break;
  429.  
  430.     case OPTCOM:
  431.     case UCOPTCOM:
  432.         if (Nlines == 0)
  433.             *status = doopt (lin, &i);
  434.         else
  435.             Errcode = EBADLNR;
  436.         break;
  437.  
  438.     case QUIT:
  439.     case UCQUIT:
  440.         i++;
  441.         if (Nlines != 0)
  442.             Errcode = EBADLNR;
  443.         else if (ckupd (lin, &i, QUIT, status) == OK)
  444.             if (lin[i] == '\n')
  445.                 *status = EOF;
  446.             else
  447.                 *status = ERR;
  448.         break;
  449.  
  450.     case HELP:
  451.     case UCHELP:
  452.         i++;
  453.         if (Nlines == 0)
  454.             dohelp (lin, &i, status);
  455.         else
  456.             Errcode = EBADLNR;
  457.         break;
  458.  
  459.     case MISCCOM:        /* miscellanious features */
  460.     case UCMISCCOM:
  461.         i++;
  462.         switch (lin[i]) {
  463.         case 'b':    /* draw box */
  464.         case 'B':
  465.             defalt (Curln, Curln);
  466.             i++;
  467.             *status = draw_box (lin, &i);
  468.             break;
  469.  
  470.         default:
  471.             Errcode = EWHATZAT;
  472.             break;
  473.         }
  474.         break;
  475.  
  476.     case SHELLCOM:
  477.         if (! Unix_mode)
  478.             error ("in docmd: can't happen.");
  479.     shellcom:
  480.         i++;
  481.         defalt (Curln, Curln);
  482.         *status = doshell (lin, &i);
  483.         break;
  484.  
  485.     case '~':
  486.         if (! Unix_mode)
  487.             goto shellcom;
  488.         /* else
  489.             fall through to default
  490.             which will generate an error */
  491.  
  492.     default:
  493.         Errcode = EWHATZAT;    /* command not recognized */
  494.         break;
  495.     }
  496.  
  497.     if (*status == OK)
  498.         Probation = NO;
  499.  
  500.     return (*status);
  501. }
  502.  
  503.  
  504. /* dohelp --- display documentation about editor */
  505.  
  506. dohelp (lin, i, status)
  507. char lin[];
  508. int *i, *status;
  509. {
  510.     char filename[MAXLINE];
  511.     char swt_filename[MAXLINE];
  512.     static char helpdir[] = "/usr/local/lib/se_h";    /* help scripts */
  513.     int j;
  514.     FILE *fp, *fopen ();
  515.  
  516.     SKIPBL (lin, *i);
  517.     if (lin[*i] == NEWLINE)
  518.         sprintf (filename, "%s/elp", helpdir);
  519.     else
  520.     {
  521.         /* build filename from text after "h" */
  522.         sprintf (filename, "%s/%s", helpdir, &lin[*i]);
  523.         j = strlen (filename);
  524.         filename[j-1] = EOS;    /* lop off newline */
  525.     }
  526.  
  527.     /* map to lower case */
  528.     for (j = 0; filename[j] != EOS; j++)
  529.         if (isupper (filename[j]))
  530.             filename[j] = tolower (filename[j]);
  531.  
  532.     sprintf (swt_filename, "%s_swt", filename);
  533.  
  534.     if (! Unix_mode && access (swt_filename, 4) == 0)
  535.         strcpy (filename, swt_filename);
  536.         /* SWT version of help file exists, use it */
  537.     /* else
  538.         use Unix or normal version of the help file */
  539.  
  540.     *status = OK;
  541.     if ((fp = fopen (filename, "r")) == NULL)
  542.     {
  543.         *status = ERR;
  544.         Errcode = ENOHELP;
  545.     }
  546.     else
  547.     {
  548. #ifdef u3b2
  549.         /* 3B2 seems to have problems with stdio and malloc... */
  550.         char buf[BUFSIZ];
  551.         setbuf (fp, buf);
  552. #endif
  553.  
  554.         /* status is OK */
  555.         display_message (fp);    /* display the help script */
  556.         fclose (fp);
  557.     }
  558. }
  559.  
  560.  
  561. /* doopt --- interpret option command */
  562.  
  563. int doopt (lin, i)
  564. char lin[];
  565. int *i;
  566. {
  567.     int temp, line, stat;
  568.     char tempstr[4];
  569.     int ret;
  570.     int dosopt ();
  571.     int ctoi ();
  572.  
  573.     (*i)++;
  574.     ret = ERR;
  575.  
  576.     switch (lin[*i]) {
  577.  
  578.     case 'g':        /* substitutes in a global can(not) fail */
  579.     case 'G':
  580.         if (lin[*i + 1] == '\n')
  581.         {
  582.             ret = OK;
  583.             Globals = ! Globals;    /* toggle */
  584.             if (Globals == YES)
  585.                 remark ("failed global substitutes continue");
  586.             else
  587.                 remark ("failed global substitutes stop");
  588.         }
  589.         break;
  590.  
  591.     case 'h':
  592.     case 'H':        /* do/don't use hardware insert/delete */
  593.         if (lin[*i + 1] == '\n')
  594.         {
  595.             ret = OK;
  596.             No_hardware = ! No_hardware;
  597.             if (No_hardware == YES)
  598.                 remark ("no line insert/delete");
  599.             else
  600.                 remark ("line insert/delete");
  601.         }
  602.         break;
  603.  
  604.     case 'k':        /* tell user if buffer saved or not */
  605.     case 'K':
  606.         if (lin[*i + 1] == '\n')
  607.         {
  608.             ret = OK;
  609.             if (Buffer_changed == YES)
  610.                 remark ("not saved");
  611.             else
  612.                 remark ("saved");
  613.         }
  614.         break;
  615.  
  616.  
  617.     case 'z':    /* suspend the editor process */
  618.     case 'Z':
  619.         if (lin[*i + 1] == '\n')
  620.         {
  621.             ret = OK;
  622. #ifdef BSD
  623.             if (Catching_stops)
  624.             {
  625.                 char *getenv ();
  626.  
  627.                 /*
  628.                  * order the test this way so that it fails
  629.                  * immediately in the usual case
  630.                  */
  631.                 if (getenv ("RSE") != NULL && At_gtics)
  632.                 {
  633.                     remark ("You may not suspend me");
  634.                     break;    /* switch */
  635.                 }
  636.                 else if (Buffer_changed == YES)
  637.                     fprintf (stderr, "WARNING: buffer not saved\n");
  638.                 kill (getpid(), SIGTSTP);
  639.                 /* stop_hdlr() will do all the work for us */
  640.             }
  641. #else
  642.             remark ("process suspension not available");
  643. #endif
  644.         }
  645.         break;
  646.  
  647.     case 't':    /* set or display tab stops for expanding tabs */
  648.     case 'T':
  649.         ++(*i);
  650.         if (lin[*i] == '\n')
  651.         {
  652.             remark (Tabstr);
  653.             ret = OK;
  654.         }
  655.         else
  656.         {
  657.             ret = settab (&lin[*i]);
  658.             if (ret == OK)
  659.                 strcpy (Tabstr, &lin[*i]);
  660.             else    /* defaults were set */
  661.                 strcpy (Tabstr, "+4");
  662.         }
  663.         break;
  664.  
  665.     case 'w':    /* set or display warning column */
  666.     case 'W':
  667.         ++(*i);
  668.         if (lin[*i] == '\n')
  669.             ret = OK;
  670.         else
  671.         {
  672.             temp = ctoi (lin, i);
  673.             if (lin[*i] == '\n')
  674.                 if (temp > 0 && temp < MAXLINE - 3)
  675.                 {
  676.                     ret = OK;
  677.                     Warncol = temp;
  678.                 }
  679.                 else
  680.                     Errcode = ENONSENSE;
  681.         }
  682.         if (ret == OK)
  683.             saynum (Warncol);
  684.         break;
  685.  
  686.     case '-':    /* fix window in place on screen, or erase it */
  687.         ++(*i);
  688.         if (getnum (lin, i, &line, &stat) == EOF)
  689.         {
  690.             mesg ("", HELP_MSG);
  691.             if (Toprow > 0)
  692.             {
  693.                 Topln = max (1, Topln - Toprow);
  694.                 Toprow = 0;
  695.                 First_affected = Topln;
  696.             }
  697.             ret = OK;
  698.         }
  699.         else if (stat != ERR && lin[*i] == '\n')
  700.             if (Toprow + (line - Topln + 1) < Cmdrow)
  701.             {
  702.                 Toprow += line - Topln + 1;
  703.                 Topln = line + 1;
  704.                 for (temp = 0; temp < Ncols; temp++)
  705.                     load ('-', Toprow - 1, temp);
  706.                 if (Topln > Lastln)
  707.                     adjust_window (1, Lastln);
  708.                 if (Curln < Topln)
  709.                     Curln = min (Topln, Lastln);
  710.                 ret = OK;
  711.             }
  712.             else
  713.                 Errcode = EORANGE;
  714.         break;
  715.  
  716.     case 'a':    /* toggle absolute line numbering */
  717.     case 'A':
  718.         if (lin[*i + 1] == '\n')
  719.         {
  720.             Absnos = ! Absnos;
  721.             ret = OK;
  722.         }
  723.         break;
  724.  
  725.     case 'c':    /* toggle case option */
  726.     case 'C':
  727.         if (lin[*i + 1] == '\n')
  728.         {
  729.             ret = OK;
  730.             Invert_case = ! Invert_case;
  731.             if (Rel_a == 'A')
  732.             {
  733.                 Rel_a = 'a';
  734.                 Rel_z = 'z';
  735.             }
  736.             else
  737.             {
  738.                 Rel_a = 'A';
  739.                 Rel_z = 'Z';
  740.             }
  741.         }
  742.  
  743.         mesg (Invert_case ? "CASE" : "", CASE_MSG);
  744.         break;
  745.  
  746.     case 'd':    /* set or display placement of "." after a delete */
  747.     case 'D':
  748.         if (lin[*i + 1] == '\n')
  749.         {
  750.             if (Ddir == FORWARD)
  751.                 remark (">");
  752.             else
  753.                 remark ("<");
  754.             ret = OK;
  755.         }
  756.         else if (lin[*i + 2] != '\n')
  757.             Errcode = EODLSSGTR;
  758.         else if (lin[*i + 1] == '>')
  759.         {
  760.             ret = OK;
  761.             Ddir = FORWARD;
  762.         }
  763.         else if (lin[*i + 1] == '<')
  764.         {
  765.             ret = OK;
  766.             Ddir = BACKWARD;
  767.         }
  768.         else
  769.             Errcode = EODLSSGTR;
  770.         break;
  771.  
  772.     case 'v':    /* set or display overlay column */
  773.     case 'V':
  774.         ++(*i);
  775.         if (lin[*i] == '\n')
  776.         {
  777.             if (Overlay_col == 0)
  778.                 remark ("$");
  779.             else
  780.                 saynum (Overlay_col);
  781.             ret = OK;
  782.         }
  783.         else
  784.         {
  785.             if (lin[*i] == '$' && lin[*i + 1] == '\n')
  786.             {
  787.                 Overlay_col = 0;
  788.                 ret = OK;
  789.             }
  790.             else
  791.             {
  792.                 temp = ctoi (lin, i);
  793.                 if (lin[*i] == '\n')
  794.                 {
  795.                     Overlay_col = temp;
  796.                     ret = OK;
  797.                 }
  798.                 else
  799.                     Errcode = ENONSENSE;
  800.             }
  801.         }
  802.         break;
  803.  
  804.     case 'u':    /* set or display character for unprintable chars */
  805.     case 'U':
  806.         if (lin[*i + 1] == '\n')
  807.         {
  808.             ret = OK;
  809.             tempstr[0] = tempstr[2] = '"';
  810.             tempstr[1] = Unprintable;
  811.             tempstr[3] = EOS;
  812.             remark (tempstr);
  813.         }
  814.         else if (lin[*i + 2] == '\n')
  815.         {
  816.             if (lin[*i + 1] < ' ' || lin[*i + 1] >= DEL)
  817.                 Errcode = ENONSENSE;
  818.             else 
  819.             {
  820.                 ret = OK;
  821.                 if (Unprintable != lin[*i + 1])
  822.                 {
  823.                     Unprintable = lin[*i + 1];
  824.                     First_affected = Topln;
  825.                 }
  826.             }
  827.         }
  828.         break;
  829.  
  830.     case 'l':    /* set or display line number display option */
  831.     case 'L':
  832.         if (lin[*i+1] == '\n')
  833.         {
  834.             Nchoise = EOS;
  835.             ret = OK;
  836.         }
  837.         else if (lin[*i + 2] == '\n' && 
  838.             (lin[*i + 1] == CURLINE || lin[*i + 1] == LASTLINE
  839.             || lin[*i + 1] == TOPLINE))
  840.         {
  841.             Nchoise = lin[*i + 1];
  842.             ret = OK;
  843.         }
  844.         else if (lin[*i + 1] == 'm' || lin[*i + 1] == 'M')
  845.         {
  846.             /* set or display the left margin */
  847.             (*i)++;
  848.             if (lin[*i + 1] == '\n')
  849.             {
  850.                 saynum (Firstcol + 1);
  851.                 ret = OK;
  852.             }
  853.             else 
  854.             {
  855.                 (*i)++;
  856.                 temp = ctoi (lin, i);
  857.                 if (lin[*i] == '\n')
  858.                     if (temp > 0 && temp < MAXLINE)
  859.                     {
  860.                         First_affected = Topln;
  861.                         Firstcol = temp - 1;
  862.                         ret = OK;
  863.                     }
  864.                     else
  865.                         Errcode = ENONSENSE;
  866.             }
  867.         }
  868.         break;
  869.  
  870.     case 'f':    /* fortran (ugh, yick, gross) options */
  871.     case 'F':
  872.         if (lin[*i + 1] == '\n')
  873.             ret = dosopt ("f");
  874.         break;
  875.  
  876.     case 's':    /* set source options */
  877.     case 'S':
  878.         ret = dosopt (&lin[*i + 1]);
  879.         break;
  880.  
  881.     case 'i':    /* set or display indent option */
  882.     case 'I':
  883.         ++(*i);
  884.         if (lin[*i] == '\n')
  885.             ret = OK;
  886.         else if ((lin[*i] == 'a' || lin[*i] == 'A') && lin[*i + 1] == '\n')
  887.         {
  888.             Indent = 0;
  889.             ret = OK;
  890.         }
  891.         else
  892.         {
  893.             temp = ctoi (lin, i);
  894.             if (lin[*i] == '\n')
  895.                 if (temp > 0 && temp < MAXLINE - 3)
  896.                 {
  897.                     ret = OK;
  898.                     Indent = temp;
  899.                 }
  900.                 else
  901.                     Errcode = ENONSENSE;
  902.         }
  903.         if (ret == OK)
  904.             if (Indent > 0)
  905.                 saynum (Indent);
  906.             else
  907.                 remark ("auto");
  908.         break;
  909.  
  910.     case 'm':    /* toggle mail notification */
  911.     case 'M':
  912.         if (lin[*i + 1] == '\n')
  913.         {
  914.             Notify = ! Notify;    /* toggle notification */
  915.             remark (Notify ? "notify on" : "notify off");
  916.             ret = OK;
  917.         }
  918.         break;
  919.  
  920.     case 'p':        /* toggle pattern and command style */
  921.     case 'P':        /* if additional letter there, it forces mode */
  922.         ret = OK;
  923.         switch (lin[*i + 1]) {
  924.         case EOS:
  925.         case '\n':    /* toggle */
  926.             if (Unix_mode)
  927.                 goto no_unix;
  928.                 /* currently in Unix mode */
  929.                 /* switch to SWT style patterns */
  930.             else
  931.                 goto yes_unix;
  932.                 /* currently in SWT mode */
  933.                 /* switch to Unix style patterns */
  934.  
  935.             break;
  936.  
  937.         case 's':    /* force SWT mode */
  938.         case 'S':
  939.     no_unix:    Unix_mode = NO;
  940.             BACKSCAN = '\\';
  941.             NOTINCCL = '~';
  942.             XMARK = '!';
  943.             ESCAPE = '@';
  944.             break;
  945.  
  946.         case 'u':    /* force UNIX mode */
  947.         case 'U':
  948.     yes_unix:    Unix_mode = YES;
  949.             BACKSCAN = '?';
  950.             NOTINCCL = '^';
  951.             XMARK = '~';
  952.             ESCAPE = '\\';
  953.             break;
  954.         
  955.         default:
  956.             Errcode = EOWHAT;
  957.             ret = ERR;
  958.             goto out_of_here;
  959.         }
  960.         set_patterns (Unix_mode);
  961.         mesg (Unix_mode ? "UNIX" : "SWT", MODE_MSG);
  962.     out_of_here:
  963.         break;
  964.     
  965.     case 'x':
  966.     case 'X':    /* toggle tab compression */
  967.         if (lin[*i + 1] == '\n')
  968.         {
  969.             ret = OK;
  970.             Compress = ! Compress;
  971.             mesg (Compress ? "XTABS" : "", COMPRESS_MSG);
  972.         }
  973.         break;
  974.  
  975.     case 'y':    /* encrypt files */
  976.     case 'Y':
  977.         if (lin[*i + 1] == '\n')
  978.         {
  979.         crypt_toggle:
  980.             ret = OK;
  981.             Crypting = ! Crypting;
  982.             if (Crypting )
  983.                 do {
  984.                     getkey ();
  985.                     if (Key[0] == EOS)
  986.                         remark ("Empty keys are not allowed.\n");
  987.                 } while (Key[0] == EOS);
  988.             else
  989.                 Key[0] = EOS;
  990.         }
  991.         else
  992.         {
  993.             register int j;
  994.  
  995.             ret = OK;
  996.             (*i)++;        /* *i was the 'y' */
  997.             while (isspace (lin[*i]) && lin[*i] != '\n')
  998.                 (*i)++;
  999.             if (lin[*i] != '\n' && lin[*i] != EOS)
  1000.             {
  1001.                 for (j = 0; lin[*i] != '\n' && lin[*i] != EOS;
  1002.                     j++, (*i)++)
  1003.                     Key[j] = lin[*i];
  1004.                 Key[j] = EOS;
  1005.                 Crypting = YES;
  1006.             }
  1007.             else
  1008.                 goto crypt_toggle;
  1009.         }
  1010.         mesg (Crypting ? "ENCRYPT" : "", CRYPT_MSG);
  1011.         break;
  1012.  
  1013.     default:
  1014.         Errcode = EOWHAT;
  1015.  
  1016.     }
  1017.  
  1018.     return (ret);
  1019. }
  1020.  
  1021.  
  1022. /* domark --- name lines line1 through line2 as kname */
  1023.  
  1024. int domark (kname)
  1025. char kname;
  1026. {
  1027.     int line;
  1028.     int ret;
  1029.     register LINEDESC *k;
  1030.     LINEDESC *getind ();
  1031.  
  1032.     if (Line1 <= 0)
  1033.     {
  1034.         Errcode = EORANGE;
  1035.         ret = ERR;
  1036.     }
  1037.     else
  1038.     {
  1039.         k = getind (Line1);
  1040.         for (line = Line1; line <= Line2; line++)
  1041.         {
  1042.             if (intrpt())
  1043.                 return (ERR);
  1044.             k -> Markname = kname;
  1045.             k = NEXTLINE(k);
  1046.         }
  1047.         ret = OK;
  1048.     }
  1049.     return (ret);
  1050. }
  1051.  
  1052.  
  1053. /* doprnt --- set curln, locate window */
  1054.  
  1055. int doprnt (from, to)
  1056. int from, to;
  1057. {
  1058.  
  1059.     if (from <= 0)
  1060.     {
  1061.         Errcode = EORANGE;
  1062.         return (ERR);
  1063.     }
  1064.  
  1065.     adjust_window (from, to);
  1066.     Curln = to;
  1067.     return (OK);
  1068. }
  1069.  
  1070.  
  1071. /* doread --- read "file" after "line" */
  1072.  
  1073. int doread (line, file, tflag)
  1074. int line;
  1075. char *file;
  1076. int tflag;
  1077. {
  1078.     register int count, len, i;
  1079.     int ret;
  1080.     int strlen ();
  1081.     FILE *fd;
  1082.     FILE *fopen (), *crypt_open ();
  1083.     char lin1[MAXLINE], lin2[MAXLINE];
  1084.     char *fgets ();
  1085.     register LINEDESC *ptr;
  1086.     LINEDESC *sp_inject ();
  1087.     LINEDESC *getind ();
  1088.     char *expand_env ();
  1089.  
  1090.     file = expand_env (file);    /* expand $HOME, etc. */
  1091.  
  1092.     if (Savfil[0] == EOS)
  1093.     {
  1094.         strcpy (Savfil, file);
  1095.         mesg (Savfil, FILE_MSG);
  1096.     }
  1097.  
  1098.     if (Crypting)
  1099.         fd = crypt_open (file, "r");
  1100.     else
  1101.         fd = fopen (file, "r");
  1102.  
  1103.     if (fd == NULL)
  1104.     {
  1105.         ret = ERR;
  1106.         Errcode = ECANTREAD;
  1107.     }
  1108.     else
  1109.     {
  1110.         First_affected = min (First_affected, line + 1);
  1111.         ptr = getind (line);
  1112.         ret = OK;
  1113. #ifndef OLD_SCRATCH
  1114.         Curln = line;
  1115. #endif
  1116.         remark ("reading");
  1117.         for (count = 0; fgets (lin1, MAXLINE, fd) != NULL; count++)
  1118.         {
  1119.             if (intrpt ())
  1120.             {
  1121.                 ret = ERR;
  1122.                 break;
  1123.             }
  1124.             if (Compress == NO && tflag == NO)
  1125.                 ptr = sp_inject (lin1, strlen (lin1), ptr);
  1126.             else
  1127.             {
  1128.                 len = 0;
  1129.                 for (i = 0; lin1[i] != EOS && len < MAXLINE - 1; i++)
  1130.                     if (lin1[i] != '\t')
  1131.                         lin2[len++] = lin1[i];
  1132.                     else
  1133.                         do
  1134.                             lin2[len++] = ' ';
  1135.                         while (len % 8 != 0 
  1136.                             && len < MAXLINE - 1);
  1137.                 lin2[len] = EOS;
  1138.                 if (len >= MAXLINE)
  1139.                 {
  1140.                     ret = ERR;
  1141.                     Errcode = ETRUNC;
  1142.                 }
  1143.                 ptr = sp_inject (lin2, len, ptr);
  1144.             }
  1145.             if (ptr == NOMORE)
  1146.             {
  1147.                 ret = ERR;
  1148.                 break;
  1149.             }
  1150.         }
  1151.         if (Crypting)
  1152.             crypt_close (fd);
  1153.         else
  1154.             fclose (fd);
  1155.         saynum (count);
  1156.         Curln = line + count;
  1157.         svins (line, count);
  1158.     }
  1159.  
  1160.     return (ret);
  1161. }
  1162.  
  1163.  
  1164. /* dosopt --- set source language-related options */
  1165.  
  1166. int dosopt (lin)
  1167. char lin[];
  1168. {
  1169.     char lang[8];
  1170.     int i;
  1171.     int strbsr ();
  1172.     static struct {
  1173.         char *txt;
  1174.         int val;
  1175.     } ltxt[] = {    
  1176.         "",     1,
  1177.         "as",   2,
  1178.         "c",    3,
  1179.         "d",    1,
  1180.         "data", 1,
  1181.         "f",    4,
  1182.         "h",    3,
  1183.         "n",    1,
  1184.         "nr",   1,
  1185.         "nroff",1,
  1186.         "p",    3,
  1187.         "r",    3,
  1188.         "s",    2,
  1189.     };
  1190.  
  1191.     i = 0;
  1192.     getwrd (lin, &i, lang, 8);
  1193.  
  1194.     strmap (lang, 'a');
  1195.  
  1196.     i = strbsr ((char *)ltxt, sizeof (ltxt), sizeof (ltxt[0]), lang);
  1197.     if (i == EOF)
  1198.     {
  1199.         Errcode = ENOLANG;
  1200.         return (ERR);
  1201.     }
  1202.  
  1203.     switch (ltxt[i].val) {
  1204.     case 1:
  1205.         Warncol = 74;
  1206.         Rel_a = 'A';
  1207.         Rel_z = 'Z';
  1208.         Invert_case = NO;
  1209.         strcpy (Tabstr, "+4");
  1210.         settab (Tabstr);
  1211.         Compress = NO;
  1212.         break;
  1213.  
  1214.     case 3:
  1215.         Warncol = 74;
  1216.         Rel_a = 'A';
  1217.         Rel_z = 'Z';
  1218.         Invert_case = NO;
  1219.         strcpy (Tabstr, "+8");
  1220.         settab (Tabstr);
  1221.         Compress = YES;
  1222.         break;
  1223.     case 4:
  1224.         Warncol = 72;
  1225.         Rel_a = 'A';
  1226.         Rel_z = 'Z';
  1227.         Invert_case = NO;
  1228.         strcpy (Tabstr, "7+3");
  1229.         settab (Tabstr);
  1230.         Compress = YES;
  1231.         break;
  1232.  
  1233.     case 2:
  1234.         Warncol = 72;
  1235.         Rel_a = 'A';
  1236.         Rel_z = 'Z';
  1237.         Invert_case = NO;
  1238.         strcpy (Tabstr, "17+8");
  1239.         settab (Tabstr);
  1240.         Compress = YES;
  1241.         break;
  1242.     }
  1243.  
  1244.     mesg (Invert_case == YES ? "CASE" : "", CASE_MSG);
  1245.     mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG);
  1246.  
  1247.     return (OK);
  1248. }
  1249.  
  1250.  
  1251. /* dotlit --- transliterate characters */
  1252.  
  1253. int dotlit (sub, allbut)
  1254. char sub[];
  1255. int allbut;
  1256. {
  1257.     char new[MAXLINE];
  1258.     char kname;
  1259.     int collap, x, i, j, line, lastsub, status;
  1260.     int ret;
  1261.     LINEDESC *inx;
  1262.     LINEDESC *gettxt (), *getind ();
  1263.  
  1264.     ret = ERR;
  1265.     if (Line1 <= 0)
  1266.     {
  1267.         Errcode = EORANGE;
  1268.         return (ret);
  1269.     }
  1270.  
  1271.     if (First_affected > Line1)
  1272.         First_affected = Line1;
  1273.  
  1274.     lastsub = strlen (sub) - 1;
  1275.     if ((strlen (Tlpat)  - 1) > lastsub || allbut == YES)
  1276.         collap = YES;
  1277.     else
  1278.         collap = NO;
  1279.  
  1280.     for (line = Line1; line <= Line2; line++)
  1281.     {
  1282.         if (intrpt ())    /* check for interrupts */
  1283.             return (ERR);
  1284.  
  1285.         inx = gettxt (line);    /* get text of line into txt, return index */
  1286.         j = 0;
  1287.         for (i = 0; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1288.         {
  1289.             x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1290.             if (collap == YES && x >= lastsub && lastsub >= 0)    /* collapse */
  1291.             {
  1292.                 new[j] = sub[lastsub];
  1293.                 j++;
  1294.                 for (i++; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1295.                 {
  1296.                     x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1297.                     if (x < lastsub)
  1298.                         break;
  1299.                 }
  1300.             }
  1301.             if (Txt[i] == EOS || Txt[i] == '\n')
  1302.                 break;
  1303.             if (x >= 0 && lastsub >= 0)    /* transliterate */
  1304.             {
  1305.                 new[j] = sub[x];
  1306.                 j++;
  1307.             }
  1308.             else if (x < 0)        /* copy */
  1309.             {
  1310.                 new[j] = Txt[i];
  1311.                 j++;
  1312.             }
  1313.             /* else
  1314.                 delete */
  1315.         }
  1316.  
  1317.         if (Txt[i] == '\n')    /* add a newline, if necessary */
  1318.         {
  1319.             new[j] = '\n';
  1320.             j++;
  1321.         }
  1322.         new[j] = EOS;        /* add the EOS */
  1323.  
  1324.         kname = inx -> Markname;    /* save the markname */
  1325.         delete (line, line, &status);
  1326.         ret = inject (new);
  1327.         if (ret == ERR)
  1328.             break;
  1329.         inx = getind (Curln);
  1330.         inx -> Markname = kname;    /* set markname */
  1331.         ret = OK;
  1332.         Buffer_changed = YES;
  1333.     }
  1334.  
  1335.     return (ret);
  1336. }
  1337.  
  1338. /* doundo --- restore last set of lines deleted */
  1339.  
  1340. int doundo (dflg, status)
  1341. int dflg;
  1342. int *status;
  1343. {
  1344.     LINEDESC *l1, *l2, *k1, *k2;
  1345.     LINEDESC *getind ();
  1346.     int oldcnt;
  1347.     int nextln (), prevln ();
  1348.  
  1349.     *status = ERR;
  1350.     if (dflg == NO && Line1 <= 0)
  1351.         Errcode = EORANGE;
  1352.     else if (Limbo == NOMORE)
  1353.         Errcode = ENOLIMBO;
  1354.     else if (Line1 > Line2)
  1355.         Errcode = EBACKWARD;
  1356.     else if (Line2 > Lastln)
  1357.         Errcode = ELINE2;
  1358.     else
  1359.     {
  1360.         *status = OK;
  1361.         Curln = Line2;
  1362. #ifdef OLD_SCRATCH
  1363.         k1 = getind (Line2);
  1364.         k2 = getind (nextln (Line2));
  1365.         l1 = Limbo;
  1366.         l2 = l1 -> Prevline;
  1367.         relink (k1, l1, l2, k2);
  1368.         relink (l2, k2, k1, l1);
  1369. #else
  1370.         blkmove (Limbo - Buf, MAXBUF - 1, Line2);
  1371. #endif
  1372.         svins (Line2, Limcnt);
  1373.         oldcnt = Limcnt;
  1374.         Limcnt = 0;
  1375.         Limbo = NOMORE;
  1376.         Lastln += oldcnt;
  1377.         if (dflg == NO)
  1378.             delete (Line1, Line2, status);
  1379.         Curln += oldcnt;
  1380.         if (First_affected > Line1)
  1381.             First_affected = Line1;
  1382.     }
  1383.  
  1384.     return (*status);
  1385. }
  1386.  
  1387. /* dowrit --- write "from" through "to" into file */
  1388.  
  1389. int dowrit (from, to, file, aflag, fflag, tflag)
  1390. int from, to, aflag, fflag, tflag;
  1391. char *file;
  1392. {
  1393.     FILE *fd;
  1394.     FILE *fopen (), *crypt_open ();
  1395.     register int line, ret, i, j;
  1396.     int strcmp (), access ();
  1397.     char tabs[MAXLINE];
  1398.     register LINEDESC *k;
  1399.     LINEDESC *getind ();
  1400.     char *expand_env ();
  1401.  
  1402.     ret = ERR;
  1403.     if (from <= 0)
  1404.         Errcode = EORANGE;
  1405.  
  1406.     else
  1407.     {
  1408.         file = expand_env (file);    /* expand $HOME, etc. */
  1409.  
  1410.         if (aflag == YES)
  1411.         {
  1412.             if (Crypting)
  1413.                 fd = crypt_open (file, "a");
  1414.             else
  1415.                 fd = fopen (file, "a");
  1416.         }
  1417.         else if (strcmp (file, Savfil) == 0 || fflag == YES
  1418.             || Probation == WRITECOM || access (file, 0) == -1)
  1419.         {
  1420.             if (Crypting)
  1421.                 fd = crypt_open (file, "w");
  1422.             else
  1423.                 fd = fopen (file, "w");
  1424.         }
  1425.         else
  1426.         {
  1427.             Errcode = EFEXISTS;
  1428.             Probation = WRITECOM;
  1429.             return (ret);
  1430.         }
  1431.         if (fd == NULL)
  1432.             Errcode = ECANTWRITE;
  1433.         else
  1434.         {
  1435.             ret = OK;
  1436.             remark ("writing");
  1437.             k = getind (from);
  1438.             for (line = from; line <= to; line++)
  1439.             {
  1440.                 if (intrpt ())
  1441.                     return (ERR);
  1442.                 gtxt (k);
  1443.                 if (Compress == NO && tflag == NO)
  1444.                     fputs (Txt, fd);
  1445.                 else
  1446.                 {
  1447.                     for (i = 0; Txt[i] == ' '; i++)
  1448.                         ;
  1449.                     for (j = 0; j < i / 8; j++)
  1450.                         tabs[j] = '\t';
  1451.                     tabs[j] = EOS;
  1452.                     fputs (tabs, fd);
  1453.                     fputs (&Txt[j * 8], fd);
  1454.                 }
  1455.                 k = NEXTLINE(k);
  1456.             }
  1457.             if (Crypting)
  1458.                 crypt_close (fd);
  1459.             else
  1460.                 fclose (fd);
  1461.             sync ();    /* just in case the system crashes */
  1462.             saynum (line - from);
  1463.             if (from == 1 && line - 1 == Lastln)
  1464.                 Buffer_changed = NO;
  1465.         }
  1466.     }
  1467.     return (ret);
  1468. }
  1469.  
  1470. /* expand_env --- expand environment variables in file names */
  1471.  
  1472. char *expand_env (file)
  1473. register char *file;
  1474. {
  1475.     register int i, j, k;    /* indices */
  1476.     char *getenv ();
  1477.     char var[MAXLINE];        /* variable name */
  1478.     char *val;            /* value of environment variable */
  1479.     static char buf[MAXLINE * 2];    /* expanded file name, static to not go away */
  1480.  
  1481.  
  1482.     i = j = k = 0;
  1483.     while (file[i] != EOS)
  1484.     {
  1485.         if (file[i] == ESCAPE)
  1486.         {
  1487.             if (file[i+1] == '$')
  1488.             {
  1489.                 buf[j++] = file[++i];    /* the actual $ */
  1490.                 i++;    /* for next time around the loop */
  1491.             }
  1492.             else
  1493.                 buf[j++] = file[i++];    /* the \ */
  1494.         }
  1495.         else if (file[i] != '$')    /* normal char */
  1496.             buf[j++] = file[i++];
  1497.         else            /* environment var */
  1498.         {
  1499.             i++;    /* skip $ */
  1500.             k = 0;
  1501.             while (file[i] != '/' && file[i] != EOS)
  1502.                 var[k++] = file[i++];    /* get var name */
  1503.             var[k] = EOS;
  1504.  
  1505.             if ((val = getenv (var)) != NULL)
  1506.                 for (k = 0; val[k] != EOS; k++)
  1507.                     buf[j++] = val[k];
  1508.                     /* copy val into file name */
  1509.             /* else
  1510.                 var not in enviroment; leave file
  1511.                 name alone, multiple slashes are legal */
  1512.         }
  1513.     }
  1514.     buf[j] = EOS;
  1515.  
  1516.     return (buf);
  1517. }
  1518.  
  1519. /* crypt_open -- run files through crypt */
  1520.  
  1521. FILE *crypt_open (file, mode)
  1522. char *file, *mode;
  1523. {
  1524.     char buf[MAXLINE];
  1525.     FILE *fp, *popen ();
  1526.  
  1527.     if (! Crypting)
  1528.         return (NULL);
  1529.  
  1530.     while (Key[0] == EOS)
  1531.     {
  1532.         getkey ();
  1533.         if (Key[0] == EOS)
  1534.             printf ("The key must be non-empty!\n");
  1535.     }
  1536.  
  1537.     switch (mode[0]) {
  1538.     case 'r':
  1539.         sprintf (buf, "crypt %s < %s", Key, file);
  1540.         fp = popen (buf, "r");
  1541.         return (fp);        /* caller checks for NULL or not */
  1542.         break;
  1543.  
  1544.     case 'w':
  1545.         sprintf (buf, "crypt %s > %s", Key, file);
  1546.         fp = popen (buf, "w");
  1547.         return (fp);        /* caller checks for NULL or not */
  1548.         break;
  1549.  
  1550.     case 'a':
  1551.         sprintf (buf, "crypt %s >> %s", Key, file);
  1552.         fp = popen (buf, "w");
  1553.         return (fp);        /* caller checks for NULL or not */
  1554.         break;
  1555.     
  1556.     default:
  1557.         return (NULL);
  1558.     }
  1559. }
  1560.  
  1561. crypt_close (fp)
  1562. FILE *fp;
  1563. {
  1564.     pclose (fp);
  1565. }
  1566.  
  1567. /* getkey -- get an encryption key from the user */
  1568.  
  1569. #define repeat        do
  1570. #define until(cond)    while(!(cond))
  1571.  
  1572. getkey ()
  1573. {
  1574.     char *getpass ();    /* get input w/out echoing on screen */
  1575.  
  1576.     clrscreen ();        /* does NOT wipe out Screen_image */
  1577.     tflush ();
  1578.  
  1579.     ttynormal ();
  1580.  
  1581.     repeat
  1582.     {
  1583.         strcpy (Key, getpass ("Enter encryption key: "));
  1584.         if (strcmp (Key, getpass ("Again: ")) != 0)
  1585.         {
  1586.             Key[0] = EOS;
  1587.             fprintf (stderr, "didn't work. try again.\n");
  1588.         }
  1589.         /* else
  1590.             all ok */
  1591.     } until (Key[0] != EOS);
  1592.  
  1593.     ttyedit ();
  1594.  
  1595.     restore_screen ();
  1596. }
  1597. SHAR_EOF
  1598. fi
  1599. echo shar: "extracting 'docmd2.c'" '(18236 characters)'
  1600. if test -f 'docmd2.c'
  1601. then
  1602.     echo shar: "will not over-write existing file 'docmd2.c'"
  1603. else
  1604. cat << \SHAR_EOF > 'docmd2.c'
  1605. /*
  1606. ** docmd2.c
  1607. **
  1608. ** routines to actually execute commands
  1609. */
  1610.  
  1611. #include "se.h"
  1612. #include "extern.h"
  1613.  
  1614.  
  1615. /* append --- append lines after "line" */
  1616.  
  1617. append (line, str)
  1618. int line;
  1619. char str[];
  1620. {
  1621.     char lin[MAXLINE];
  1622.     char term;
  1623.     int ret;
  1624.     int len, i, dpos, dotseen;
  1625.     int inject ();
  1626.  
  1627.     Curln = line;
  1628.  
  1629.     if (str[0] == ':')    /* text to be added is in the command line */
  1630.         ret = inject (&str[1]);
  1631.     else
  1632.     {
  1633.         Cmdrow = Toprow + (Curln - Topln) + 1;  /* 1 below Curln */
  1634.         lin[0] = EOS;
  1635.         if (Indent > 0 || line <= 0)
  1636.             len = max (0, Indent - 1);
  1637.         else /* do auto indent */
  1638.         {
  1639.             LINEDESC *k, *gettxt ();
  1640.             k = gettxt (line);
  1641.             for (len = 0; Txt[len] == ' '; len++)
  1642.                 ;
  1643.         }
  1644.         dpos = len;     /* position for terminating '.' */
  1645.  
  1646.         for (ret = NOSTATUS; ret == NOSTATUS; )
  1647.         {
  1648.             if (! hwinsdel())   /* do it the old, slow way */
  1649.             {
  1650.                 if (Cmdrow > Botrow)
  1651.                 {
  1652.                     Cmdrow = Toprow + 1;
  1653.                     cprow (Botrow, Toprow);
  1654.                     adjust_window (Curln, Curln);
  1655.                     if (First_affected > Topln)
  1656.                         First_affected = Topln;
  1657.                 }
  1658.                 clrrow (Cmdrow);
  1659.                 if (Cmdrow < Botrow)
  1660.                     clrrow (Cmdrow + 1);
  1661.             }
  1662.             else    /* try to be smart about it */
  1663.             {
  1664.                 if (Cmdrow > Botrow)
  1665.                 {
  1666.                     Cmdrow--;
  1667.                     dellines (Toprow, 1);
  1668.                     inslines (Cmdrow, 1);
  1669.                     Topln++;
  1670.                 }
  1671.                 else
  1672.                 {
  1673.                     dellines (Botrow, 1);
  1674.                     inslines (Cmdrow, 1);
  1675.                 }
  1676.             }
  1677.             prompt ("apd>");
  1678.             do
  1679.                 getcmd (lin, Firstcol, &len, &term);
  1680.             while (term == CURSOR_UP || term == CURSOR_DOWN
  1681.                 || term == CURSOR_SAME);
  1682.  
  1683.             dotseen = 0;
  1684.             if (lin[0] == '.' && lin[1] == '\n' && lin[2] == EOS)
  1685.                 dotseen = 1;
  1686.             for (i = 0; i < dpos && lin[i] == ' '; i++)
  1687.                 ;
  1688.             if (i == dpos && lin[dpos] == '.' && lin[dpos + 1] == '\n'
  1689.                 && lin[dpos+2] == EOS)
  1690.                 dotseen = 1;
  1691.  
  1692.             if (dotseen)
  1693.             {
  1694.                 if (hwinsdel())
  1695.                 {
  1696.                     dellines (Cmdrow, 1);
  1697.                     inslines (Botrow, 1);
  1698.                 }
  1699.                 ret = OK;
  1700.             }
  1701.             else if (inject (lin) == ERR)
  1702.                 ret = ERR;
  1703.             else            /* inject occured */
  1704.                 prompt ("");    /* erase prompt */
  1705.             Cmdrow++;
  1706.             if (term != FUNNY)
  1707.             {
  1708.                 if (Indent > 0)
  1709.                     len = Indent - 1;
  1710.                 else /* do auto indent */
  1711.                     for (len = 0; lin[len] == ' '; len++)
  1712.                         ;
  1713.                 dpos = len;
  1714.                 lin[0] = EOS;
  1715.             }
  1716.         }
  1717.         Cmdrow = Botrow + 1;
  1718.         if (hwinsdel())            /* since we take control */
  1719.         {                /* of the screen, we're sure */
  1720.             Sctop = Topln;        /* it's still OK */
  1721.  
  1722.             for (i = 0; i < Sclen; i++)
  1723.                 Scline[i] = Sctop + i <= Lastln ? i : -1;
  1724.         }
  1725.     }
  1726.     if (Curln == 0 && Lastln > 0)   /* for 0a or 1i followed by "." */
  1727.         Curln = 1;
  1728.     if (First_affected > line)
  1729.         First_affected = line;
  1730.  
  1731.     tflush ();
  1732.     return (ret);
  1733. }
  1734.  
  1735. /* copy --- copy line1 through line2 after line3 */
  1736.  
  1737. int copy (line3)
  1738. int line3;
  1739. {
  1740.     register int i;
  1741.     int ret;
  1742.     register LINEDESC *ptr3, *after3, *k;
  1743.     LINEDESC *getind ();
  1744.  
  1745.     ret = ERR;
  1746.  
  1747. #ifdef OLD_SCRATCH
  1748.     ptr3 = getind (line3);
  1749.     after3 = ptr3 -> Nextline;
  1750. #endif
  1751.  
  1752.     if (Line1 <= 0)
  1753.         Errcode = EORANGE;
  1754.     else
  1755.     {
  1756.         ret = OK;
  1757.         Curln = line3;
  1758.         k = getind (Line1);
  1759.         for (i = Line1; i <= Line2; i++)
  1760.         {
  1761.             gtxt (k);
  1762.             if (inject (Txt) == ERR || intrpt ())
  1763.             {
  1764.                 ret = ERR;
  1765.                 break;
  1766.             }
  1767. #ifdef OLD_SCRATCH
  1768.             if (k == ptr3)        /* make sure we don't copy stuff */
  1769.                 k = after3;    /* that's already been copied */
  1770.             else
  1771.                 k = k -> Nextline;
  1772. #else
  1773.             if (Line1 < line3)
  1774.                 k++;
  1775.             else
  1776.                 k += 2;
  1777.             /*
  1778.              * inject calls blkmove, which will shift the
  1779.              * lines down one in the array, so we add two
  1780.              * instead of one to get to the next line.
  1781.              */
  1782. #endif
  1783.         }
  1784.         First_affected = min (First_affected, line3 + 1);
  1785.     }
  1786.     return (ret);
  1787. }
  1788.  
  1789.  
  1790. /* delete --- delete lines from through to */
  1791.  
  1792. int delete (from, to, status)
  1793. int from, to, *status;
  1794. {
  1795.     int nextln (), prevln ();
  1796.     LINEDESC *k1, *k2, *j1, *j2, *l1;
  1797.     LINEDESC *getind ();
  1798.  
  1799.     if (from <= 0)          /* can't delete line 0 */
  1800.     {
  1801.         *status = ERR;
  1802.         Errcode = EORANGE;
  1803.     }
  1804.     else
  1805.     {
  1806.         if (First_affected > from)
  1807.             First_affected = from;
  1808. #ifdef OLD_SCRATCH
  1809.         k1 = getind (prevln (from));
  1810.         j1 = k1 -> Nextline;
  1811.         j2 = getind (to);
  1812.         k2 = j2 -> Nextline;
  1813.         relink (k1, k2, k1, k2);        /* close chain around deletion */
  1814. #else
  1815.         blkmove (from, to, MAXBUF - 1);    /* stick at end of buffer */
  1816. #endif
  1817.  
  1818.         Lastln -= to - from + 1;        /* adjust number of last line */
  1819.         Curln = prevln (from);
  1820.  
  1821. #ifdef OLD_SCRATCH
  1822.         if (Limbo != NOMORE)            /* discard lines in limbo */
  1823.         {
  1824.             l1 = Limbo -> Prevline;
  1825.             Limbo -> Prevline = Free;
  1826.             Free = l1;
  1827.         }
  1828. #endif
  1829.  
  1830.         Lost_lines += Limcnt;
  1831.         Limcnt = to - from + 1;        /* number of lines "deleted" */
  1832.  
  1833. #ifdef OLD_SCRATCH
  1834.         Limbo = j1;     /* put what we just deleted in limbo */
  1835.         relink (j2, j1, j2, j1);        /* close the ring */
  1836. #else
  1837.         /* point at first deleted */
  1838.         Limbo = &Buf[MAXBUF - (to - from + 1)];
  1839. #endif
  1840.         *status = OK;
  1841.         svdel (from, to - from + 1);
  1842.         Buffer_changed = YES;
  1843.     }
  1844.  
  1845.     return (*status);
  1846. }
  1847.  
  1848.  
  1849. /* join --- join a group of lines into a single line */
  1850.  
  1851. int join (sub)
  1852. char sub[];
  1853. {
  1854.     char new[MAXLINE];
  1855.     register int l, line, sublen;
  1856.     int ret;
  1857.     int inject (), delete (), prevln (), strlen ();
  1858.     register LINEDESC *k;
  1859.     LINEDESC *getind ();
  1860.  
  1861.     ret = OK;
  1862.     if (Line1 <= 0)
  1863.     {
  1864.         Errcode = EORANGE;
  1865.         return (ERR);
  1866.     }
  1867.  
  1868.     sublen = strlen (sub) + 1;      /* length of separator & EOS */
  1869.     line = Line1;
  1870.     k = getind (line);
  1871.     gtxt (k);
  1872.     move_ (Txt, new, (int) k -> Lineleng);    /* move in first chunk */
  1873.     l = k -> Lineleng;
  1874.  
  1875.     for (line++; line <= Line2; line++)
  1876.     {
  1877.         if (intrpt ())
  1878.             return (ERR);
  1879.         if (new[l - 2] == '\n') /* zap the NEWLINE */
  1880.             l--;
  1881.         k = NEXTLINE(k);    /* get the next line */
  1882.         gtxt (k);
  1883.         if (l + sublen - 1 + k -> Lineleng - 1 > MAXLINE)    /* won't fit */
  1884.         {
  1885.             Errcode = E2LONG;
  1886.             return (ERR);
  1887.         }
  1888.         move_ (sub, &new[l - 1], sublen);    /* insert separator string */
  1889.         l += sublen - 1;
  1890.         move_ (Txt, &new[l - 1], (int) k -> Lineleng);    /* move next line */
  1891.         l += k -> Lineleng - 1;
  1892.     }
  1893.     Curln = Line2;          /* all this will replace line1 through line2 */
  1894.     ret = inject (new);    /* inject the new line */
  1895.     if (ret == OK)
  1896.         ret = delete (Line1, Line2, &ret);    /* delete old lines */
  1897.     Curln++;
  1898.  
  1899.     if (First_affected > Curln)
  1900.         First_affected = Curln;
  1901.  
  1902.     return (ret);
  1903. }
  1904.  
  1905.  
  1906. /* move --- move line1 through line2 after line3 */
  1907.  
  1908. int move (line3)
  1909. int line3;
  1910. {
  1911.     int nextln (), prevln ();
  1912.     LINEDESC *k0, *k1, *k2, *k3, *k4, *k5;
  1913.     LINEDESC *getind ();
  1914.  
  1915.     if (Line1 <= 0)
  1916.     {
  1917.         Errcode = EORANGE;
  1918.         return (ERR);
  1919.     }
  1920.  
  1921.     if (Line1 <= line3 && line3 <= Line2)
  1922.     {
  1923.         Errcode = EINSIDEOUT;
  1924.         return (ERR);
  1925.     }
  1926.  
  1927. #ifdef OLD_SCRATCH
  1928.     k0 = getind (prevln (Line1));
  1929.     k1 = k0 -> Nextline;
  1930.     k2 = getind (Line2);
  1931.     k3 = k2 -> Nextline;
  1932.     relink (k0, k3, k0, k3);
  1933. #else
  1934.     blkmove (Line1, Line2, line3);
  1935. #endif
  1936.  
  1937.     if (line3 > Line1)
  1938.     {
  1939.         Curln = line3;
  1940. #ifdef OLD_SCRATCH
  1941.         line3 -= Line2 - Line1 + 1;
  1942. #endif
  1943.     }
  1944.     else
  1945.         Curln = line3 + (Line2 - Line1 + 1);
  1946.  
  1947. #ifdef OLD_SCRATCH
  1948.     k4 = getind (line3);
  1949.     k5 = k4 -> Nextline;
  1950.     relink (k4, k1, k2, k5);
  1951.     relink (k2, k5, k4, k1);
  1952. #endif
  1953.  
  1954.     Buffer_changed = YES;
  1955.     First_affected = min (First_affected, min (Line1, line3));
  1956.  
  1957.     return (OK);
  1958. }
  1959.  
  1960. /* overlay --- let user edit lines directly */
  1961.  
  1962. overlay (status)
  1963. int *status;
  1964. {
  1965.     char savtxt[MAXLINE], term, kname;
  1966.     static char empty[] = "\n";
  1967.     int lng, vcol, lcurln, scurln;
  1968.     int inject (), nextln (), prevln (), strcmp ();
  1969.     LINEDESC *indx;
  1970.     LINEDESC *getind (), *gettxt ();
  1971.  
  1972.     *status = OK;
  1973.     if (Line1 == 0)
  1974.     {
  1975.         Curln = 0;
  1976.         *status = inject (empty);
  1977.         if (*status == ERR)
  1978.             return;
  1979.         First_affected = 1;
  1980.         Line1 = 1;
  1981.         Line2++;
  1982.     }
  1983.  
  1984.     for (lcurln = Line1; lcurln <= Line2; lcurln++)
  1985.     {
  1986.         Curln = lcurln;
  1987.         vcol = Overlay_col - 1;
  1988.         do {
  1989.             adjust_window (Curln, Curln);
  1990.             updscreen ();
  1991.             Cmdrow = Curln - Topln + Toprow;
  1992.             indx = gettxt (Curln);
  1993.             lng = indx -> Lineleng;
  1994.             if (Txt[lng - 2] == '\n')       /* clobber newline */
  1995.                 lng--;
  1996.             if (vcol < 0)
  1997.                 vcol = lng - 1;
  1998.             while (lng - 1 < vcol)
  1999.             {
  2000.                 Txt[lng - 1] = ' ';
  2001.                 lng++;
  2002.             }
  2003.             Txt[lng - 1] = '\n';
  2004.             Txt[lng] = EOS;
  2005.             move_ (Txt, savtxt, lng + 1);    /* make a copy of the line */
  2006.             getcmd (Txt, Firstcol, &vcol, &term);
  2007.             if (term == FUNNY)
  2008.             {
  2009.                 if (First_affected > Curln)
  2010.                     First_affected = Curln;
  2011.                 Cmdrow = Botrow + 1;
  2012.                 return;
  2013.             }
  2014.             if (strcmp (Txt, savtxt) != 0)  /* was line changed? */
  2015.             {
  2016.                 kname = indx -> Markname;
  2017.                 delete (Curln, Curln, status);
  2018.                 scurln = Curln;
  2019.                 if (*status == OK)
  2020.                     *status = inject (Txt);
  2021.                 if (*status == ERR)
  2022.                 {
  2023.                     Cmdrow = Botrow + 1;
  2024.                     return;
  2025.                 }
  2026.                 indx = getind (nextln (scurln));
  2027.                 indx -> Markname = kname;
  2028.             }
  2029.             else
  2030.             {           /* in case end-of-line is moved */
  2031.                 if (First_affected > Curln)
  2032.                     First_affected = Curln;
  2033.             }
  2034.             switch (term) {
  2035.             case CURSOR_UP:
  2036.                 if (Curln > 1)
  2037.                     Curln--;
  2038.                 else
  2039.                     Curln = Lastln;
  2040.                 break;
  2041.             case CURSOR_DOWN:
  2042.                 if (Curln < Lastln)
  2043.                     Curln++;
  2044.                 else
  2045.                     Curln = min (1, Lastln);
  2046.                 break;
  2047.             case CURSOR_SAME:
  2048.                 vcol = 0;
  2049.                 break;
  2050.             }
  2051.         } while (term == CURSOR_UP || 
  2052.             term == CURSOR_DOWN ||
  2053.             term == CURSOR_SAME);
  2054.     }
  2055.     Cmdrow = Botrow + 1;
  2056.     return;
  2057. }
  2058.  
  2059.  
  2060. /* subst --- substitute "sub" for occurrences of pattern */
  2061.  
  2062. int subst (sub, gflag, glob)
  2063. char sub[];
  2064. int gflag, glob;
  2065. {
  2066.     char new[MAXLINE], kname;
  2067.     register int line, m, k, lastm;
  2068.     int j, junk, status, subbed, ret;
  2069.     int tagbeg[10], tagend[10];
  2070.     int amatch (), addset (), inject ();
  2071.     register LINEDESC *inx;
  2072.     LINEDESC *gettxt (), *getind ();
  2073.  
  2074.     if (Globals && glob)
  2075.         ret = OK;
  2076.     else
  2077.         ret = ERR;
  2078.  
  2079.     if (Line1 <= 0)
  2080.     {
  2081.         Errcode = EORANGE;
  2082.         return (ERR);
  2083.     }
  2084.  
  2085.     /* the following code has been removed for your protection
  2086.        index() occasionally grabs newlines out of the character class
  2087.        counter in a pattern.  for example [0-9] doesn't work due to this
  2088.  
  2089.         if (index (Pat, '\n') != -1)    # never delete NEWLINE
  2090.         {
  2091.             Errcode = EBADPAT;
  2092.             return (ERR);
  2093.         }
  2094.     */
  2095.  
  2096.     for (line = Line1; line <= Line2; line++)
  2097.     {
  2098.         if (intrpt ())
  2099.             break;
  2100.         j = 0;
  2101.         subbed = NO;
  2102.         inx = gettxt (line);
  2103.         lastm = -1;
  2104.         for (k = 0; Txt[k] != EOS; )
  2105.         {
  2106.             for (m = 1; m <= 9; m++)
  2107.             {
  2108.                 tagbeg[m] = -1;
  2109.                 tagend[m] = -1;
  2110.             }
  2111.             if (gflag == YES || subbed == NO)
  2112.                 m = amatch (Txt, k, Pat, &tagbeg[1], &tagend[1]);
  2113.             else
  2114.                 m = -1;
  2115.             if (m > -1 && lastm != m)       /* replace matched text */
  2116.             {
  2117.                 subbed = YES;
  2118.                 tagbeg[0] = k;
  2119.                 tagend[0] = m;
  2120.                 catsub (Txt, tagbeg, tagend, sub, new, &j, MAXLINE);
  2121.                 lastm = m;
  2122.             }
  2123.             if (m == -1 || m == k)  /* no match or null match */
  2124.             {
  2125.                 junk = addset (Txt[k], new, &j, MAXLINE);
  2126.                 k++;
  2127.             }
  2128.             else
  2129.                 k = m;    /* skip matched text */
  2130.         }
  2131.         if (subbed == YES)
  2132.         {
  2133.             if (addset (EOS, new, &j, MAXLINE) == NO)
  2134.             {
  2135.                 ret = ERR;
  2136.                 Errcode = E2LONG;
  2137.                 break;
  2138.             }
  2139.             kname = inx -> Markname;
  2140.             delete (line, line, &status);    /* remembers dot */
  2141.             ret = inject (new);
  2142.             if (First_affected > Curln)
  2143.                 First_affected = Curln;
  2144.             if (ret == ERR)
  2145.                 break;
  2146.             inx = getind (Curln);
  2147.             inx -> Markname = kname;
  2148.             ret = OK;
  2149.             Buffer_changed = YES;
  2150.         }
  2151.         else    /* subbed == NO */
  2152.             Errcode = ENOMATCH;
  2153.     }
  2154.  
  2155.     return (ret);
  2156. }
  2157.  
  2158.  
  2159. /* uniquely_name --- mark-name line; make sure no other line has same name */
  2160.  
  2161. uniquely_name (kname, status)
  2162. char kname;
  2163. int *status;
  2164. {
  2165.     register int line;
  2166.     register LINEDESC *k;
  2167.  
  2168.     defalt (Curln, Curln);
  2169.  
  2170.     if (Line1 <= 0)
  2171.     {
  2172.         *status = ERR;
  2173.         Errcode = EORANGE;
  2174.         return;
  2175.     }
  2176.  
  2177.     *status = OK;
  2178.     line = 0;
  2179.     k = Line0;
  2180.  
  2181.     do {
  2182.         line++;
  2183.         k = NEXTLINE(k);
  2184.         if (line == Line2)
  2185.             k -> Markname = kname;
  2186.         else if (k -> Markname == kname)
  2187.             k -> Markname = DEFAULTNAME;
  2188.     } while (line < Lastln);
  2189.  
  2190.     return;
  2191. }
  2192.  
  2193.  
  2194. /* draw_box --- draw or erase a box at coordinates in command line */
  2195.  
  2196. int draw_box (lin, i)
  2197. char lin[];
  2198. int *i;
  2199. {
  2200.     register int left, right, col, len;
  2201.     int junk;
  2202.     int ctoi (), strcmp (), inject (), delete ();
  2203.     register LINEDESC *k;
  2204.     LINEDESC *getind (), *gettxt ();
  2205.     char text[MAXLINE];
  2206.     char kname, ch;
  2207.  
  2208.     left = ctoi (lin, i);
  2209.     if (left <= 0 || left > MAXLINE)
  2210.     {
  2211.         Errcode = EBADCOL;
  2212.         return (ERR);
  2213.     }
  2214.  
  2215.     if (lin[*i] == ',')
  2216.     {
  2217.         (*i)++;
  2218.         SKIPBL (lin, *i);
  2219.         right = ctoi (lin, i);
  2220.         if (right <= 0 || right >= MAXLINE || left > right)
  2221.         {
  2222.             Errcode = EBADCOL;
  2223.             return (ERR);
  2224.         }
  2225.     }
  2226.     else
  2227.         right = left;
  2228.  
  2229.     SKIPBL (lin, *i);
  2230.     if (lin[*i] == '\n')
  2231.         ch = ' ';
  2232.     else
  2233.         ch = lin[(*i)++];
  2234.  
  2235.     if (lin[*i] != '\n')
  2236.     {
  2237.         Errcode = EEGARB;
  2238.         return (ERR);
  2239.     }
  2240.  
  2241.     if (Line1 <= 0)
  2242.     {
  2243.         Errcode = EORANGE;
  2244.         return (ERR);
  2245.     }
  2246.  
  2247.     for (Curln = Line1; Curln <= Line2; Curln++)
  2248.     {
  2249.         k = gettxt (Curln);
  2250.         len = k -> Lineleng;
  2251.         move_ (Txt, text, len);
  2252.  
  2253.         if (text[len - 2] == '\n')
  2254.             col = len - 1;
  2255.         else
  2256.             col = len;
  2257.         while (col <= right)
  2258.         {
  2259.             text[col - 1] = ' ';
  2260.             col++;
  2261.         }
  2262.         text[col - 1] = '\n';
  2263.         text[col] = EOS;
  2264.  
  2265.         if (Curln == Line1 || Curln == Line2)
  2266.             for (col = left; col <= right; col++)
  2267.                 text[col - 1] = ch;
  2268.         else
  2269.         {
  2270.             text[left - 1] = ch;
  2271.             text[right - 1] = ch;
  2272.         }
  2273.  
  2274.         if (strcmp (text, Txt) != 0)
  2275.         {
  2276.             kname = k -> Markname;
  2277.             if (delete (Curln, Curln, &junk) == ERR
  2278.                 || inject (text) == ERR)
  2279.                 return (ERR);
  2280.             k = getind (Curln);
  2281.             k -> Markname = kname;
  2282.             Buffer_changed = YES;
  2283.         }
  2284.     }
  2285.  
  2286.     Curln = Line1;        /* move to top of box */
  2287.     if (First_affected > Curln)
  2288.         First_affected = Curln;
  2289.     adjust_window (Curln, Curln);
  2290.     updscreen ();
  2291.  
  2292.     return (OK);
  2293. }
  2294.  
  2295.  
  2296. /* dfltsopt --- set the 's' option to the extension on the file name */
  2297.  
  2298. dfltsopt (name)
  2299. char name[];
  2300. {
  2301.     int i;
  2302.     int strlen (), dosopt ();
  2303.  
  2304.     for (i = strlen (name) - 1; i >= 0; i--)
  2305.         if (name[i] == '.')
  2306.         {
  2307.             dosopt (&name[i + 1]);
  2308.             break;
  2309.         }
  2310.     if (i < 0)
  2311.         dosopt ("");
  2312. }
  2313.  
  2314.  
  2315.  
  2316. /* doshell --- escape to the Shell to run one or more Unix commands */
  2317.  
  2318. /*
  2319. ** emulate vi: if running just a shell, redraw the screen as
  2320. ** soon as the shell exits. if running a program, let the user
  2321. ** redraw the screen when he/she is ready.
  2322. **
  2323. ** also emulate USG Unix 5.0 ed: a ! as the first character is
  2324. ** replaced by the previous shell command; an unescaped % is replaced
  2325. ** by the saved file name. The expanded command is echoed.
  2326. **
  2327. ** If running at ICS school at Tech, and RSE is in the environment, don't
  2328. ** allow forking, since it's called by a mail-only user.
  2329. */
  2330.  
  2331. #ifdef BSD
  2332. #define DEFAULT_PATH    "/bin/csh"
  2333. #define DEF_SHELL    "csh"
  2334. #else
  2335. #define DEFAULT_PATH    "/bin/sh"
  2336. #define DEF_SHELL    "sh"
  2337. #endif
  2338.  
  2339. int doshell (lin, pi)
  2340. char lin[];
  2341. int *pi;
  2342. {
  2343.     int forkstatus, childstatus;
  2344.     int (*save_quit)(), (*save_int)();
  2345.     int int_hdlr ();
  2346.     int (*signal())();
  2347.     int i, auto_redraw;
  2348.     char *path, *name, *p, *getenv ();
  2349.     char new_command[MAXLINE];
  2350.     int j, k;
  2351.     static char sav_com[MAXLINE] = "";
  2352.     int expanded = NO;
  2353.  
  2354.     if (At_gtics && getenv ("RSE") != NULL)    /* yes in environment */
  2355.     {
  2356.         remark ("You may not run the shell");
  2357.         return OK;    /* will wipe out command line */
  2358.     }
  2359.  
  2360.     if (Nlines == 0)        /* use normal 'ed' behavior */
  2361.     {
  2362.         tflush ();    /* flush out the terminal output */
  2363.         position_cursor (Nrows - 1, 0);    /* bottom left corner */
  2364.  
  2365.         if ((p = getenv ("SHELL")) == NULL || strcmp (p, DEFAULT_PATH) == 0)
  2366.         {
  2367.             path = DEFAULT_PATH;
  2368.             name = DEF_SHELL;    /* default */
  2369.         }
  2370. #ifdef BSD
  2371.         /* on Berkeley systems, check the other shell */
  2372.         else if (strcmp (p, "/bin/sh") == 0)
  2373.         {
  2374.             path = "/bin/sh";
  2375.             name = "sh";
  2376.         }
  2377. #endif
  2378.         else
  2379.         {
  2380.             if (p[0] == '/')    /* full pathname there */
  2381.             {
  2382.                 /* work backwards to find just name */
  2383.                 path = p;
  2384.                 i = strlen (p);
  2385.                 while (p[i] != '/')
  2386.                     i--;
  2387.                 i++;        /* skip '/' */
  2388.                 name = &p[i];
  2389.             }
  2390.             else
  2391.             {
  2392.                 char buf[MAXLINE];
  2393.  
  2394.                 sprintf (buf, "unknown shell, using %s",
  2395.                     DEF_SHELL);
  2396.                 remark (buf);
  2397.                 path = DEFAULT_PATH;
  2398.                 name = DEF_SHELL;
  2399.             }
  2400.         }
  2401.  
  2402.         auto_redraw = (lin[*pi] == '\n') ? YES : NO;
  2403.  
  2404.         /* build command, checking for leading !, and % anywhere */
  2405.         if (lin[*pi] == '!')
  2406.         {
  2407.             if (sav_com[0] != EOS)
  2408.             {
  2409.                 for (j = 0; sav_com[j] != EOS; j++)
  2410.                     new_command[j] = sav_com[j];
  2411.                 if (new_command[j-1] == '\n')
  2412.                     j--;
  2413.                 (*pi)++;
  2414.                 expanded = YES;
  2415.             }
  2416.             else
  2417.             {
  2418.                 Errcode = ENOCMD;
  2419.                 return (ERR);
  2420.             }
  2421.         }
  2422.         else
  2423.             j = 0;
  2424.  
  2425.         for (i = *pi; lin[i] != EOS; i++)
  2426.         {
  2427.             if (lin[i] == ESCAPE)
  2428.             {
  2429.                 if (lin[i+1] != '%')
  2430.                 {
  2431.                     new_command[j++] = ESCAPE;
  2432.                     new_command[j++] = lin[++i];
  2433.                 }
  2434.                 else
  2435.                     new_command[j++] = lin[++i];
  2436.             }
  2437.             else if (lin[i] == '%')
  2438.             {
  2439.                 for (k = 0; Savfil[k] != EOS; k++)
  2440.                     new_command[j++] = Savfil[k];
  2441.                 expanded = YES;
  2442.             }
  2443.             else
  2444.                 new_command[j++] = lin[i];
  2445.         }
  2446.  
  2447.         if (new_command[j-1] == '\n')
  2448.             j--;
  2449.         new_command[j] = EOS;
  2450.  
  2451.         strcpy (sav_com, new_command);    /* save it */
  2452.  
  2453.         ttynormal ();
  2454. #ifndef HARD_TERMS
  2455.         t_exit ();
  2456. #endif
  2457.         write (1, "\n\n", 2);            /* clear out a line */
  2458.  
  2459.         forkstatus = fork();
  2460.         if (forkstatus == -1)   /* the fork failed */
  2461.         {
  2462.             ttyedit ();
  2463. #ifndef HARD_TERMS
  2464.             t_init ();
  2465. #endif
  2466.             Errcode = ECANTFORK;
  2467.             return ERR;
  2468.         }
  2469.  
  2470.         if (forkstatus == 0)    /* we're in the child process */
  2471.         {
  2472.             signal (SIGINT, SIG_DFL);
  2473.             signal (SIGQUIT, SIG_DFL);
  2474. #ifdef BSD
  2475.             if (strcmp (name, "sh") != 0)    /* not /bin/sh */
  2476.                 signal (SIGTSTP, SIG_DFL);
  2477.             else
  2478.                 signal (SIGTSTP, SIG_IGN);
  2479. #endif
  2480.             if (auto_redraw)    /* no params; run a shell */
  2481.             {
  2482.                 execl (path, name, 0);
  2483.                 _exit (RETERR);   /* exec failed, notify parent */
  2484.             }
  2485.             else
  2486.             {
  2487.                 if (expanded)        /* echo it */
  2488.                     printf ("%s\n", new_command);
  2489.  
  2490.                 execl (path, name, "-c", new_command, 0);
  2491.                 _exit (RETERR);
  2492.             }
  2493.         }
  2494.  
  2495.         /* we're in the parent process here */
  2496.         save_int = signal (SIGINT, SIG_IGN);        /* ignore interrupts */
  2497.         save_quit = signal (SIGQUIT, SIG_IGN);
  2498.         while (wait (&childstatus) != forkstatus)
  2499.             ;
  2500.         save_int = signal (SIGINT, save_int);       /* catch interupts */
  2501.         save_quit = signal (SIGQUIT, save_quit);
  2502.         write (1, "\n\n", 2);    /* clear out some message space */
  2503.         Currow = Nrows - 1;
  2504.         Curcol = 0;
  2505.         if ((childstatus >> 8) != 0)
  2506.         {
  2507.             ttyedit ();
  2508. #ifndef HARD_TERMS
  2509.             t_init ();
  2510. #endif
  2511.             Errcode = ENOSHELL;
  2512.             return ERR;
  2513.         }
  2514.  
  2515. /* this was the old way, so you can compare to what we do now. */
  2516. /*
  2517. /*        if (auto_redraw)
  2518. /*        {
  2519. /*            ttyedit();
  2520. /*            restore_screen ();
  2521. /*        }
  2522. /*        else
  2523. /*            remark("Type control-q to rebuild screen");
  2524. */
  2525.  
  2526.         /* a la vi: */
  2527.         if (! auto_redraw)
  2528.         {
  2529.             int c;
  2530.  
  2531.             printf ("type return to continue: ");
  2532.             while ((c = getchar()) != '\n' && c != EOF)
  2533.                 ;
  2534.         }
  2535.  
  2536.         ttyedit ();
  2537. #ifndef HARD_TERMS
  2538.         t_init ();
  2539. #endif
  2540.         restore_screen ();
  2541.  
  2542.         return OK;
  2543.     }
  2544.  
  2545.     else
  2546.         remark ("Not implemented yet");
  2547.     
  2548.     return OK;
  2549. }
  2550. SHAR_EOF
  2551. fi
  2552. echo shar: "extracting 'misc.c'" '(3118 characters)'
  2553. if test -f 'misc.c'
  2554. then
  2555.     echo shar: "will not over-write existing file 'misc.c'"
  2556. else
  2557. cat << \SHAR_EOF > 'misc.c'
  2558. /*
  2559. ** misc.c
  2560. **
  2561. ** lots of miscellanious routines for the screen editor.
  2562. */
  2563.  
  2564. #include "se.h"
  2565. #include "extern.h"
  2566.  
  2567. /* cprow --- copy from one row to another for append */
  2568.  
  2569. cprow (from, to)
  2570. register int from, to;
  2571. {
  2572.     register int col;
  2573.  
  2574.     for (col = 0; col < Ncols; col++)
  2575.         load (Screen_image[from][col], to, col);
  2576. }
  2577.  
  2578. /* index --- return position of character in string */
  2579.  
  2580. int index (str, c)
  2581. register char str[], c;
  2582. {
  2583.     register int i;
  2584.  
  2585.     for (i = 0; str[i] != EOS; i++)
  2586.         if (str[i] == c)
  2587.             return (i);
  2588.     return (-1);
  2589. }
  2590.  
  2591. /* strbsr --- binary search stab for an entry equal to str */
  2592.  
  2593. int strbsr (stab, tsize, esize, str)
  2594. char *stab, str[];
  2595. int tsize, esize;
  2596. {
  2597.     /* stab should have been declared like this:
  2598.  
  2599.     static struct {
  2600.         char *s;
  2601.         ...
  2602.         } stab[] = {
  2603.         "string1",      ...
  2604.         "string2",      ...
  2605.         ...             ...
  2606.         };
  2607.  
  2608.     The call to strbsr should look like this:
  2609.  
  2610.     i = strbsr (stab, sizeof (stab), sizeof (stab[0]), str);
  2611.     */
  2612.  
  2613.     register int i, j, k, x;
  2614.     int strcmp ();
  2615.  
  2616.     i = 0;
  2617.     j = tsize / esize - 1;
  2618.     do {
  2619.         k = (i + j) / 2;
  2620.         if ((x = strcmp (str, *(char **)(stab + esize * k))) < 0)
  2621.             j = k - 1;              /* GREATER */
  2622.         else if (x == 0)
  2623.             return (k);             /* EQUAL */
  2624.         else
  2625.             i = k + 1;              /* LESS */
  2626.     } while (i <= j);
  2627.  
  2628.     return (EOF);
  2629. }
  2630.  
  2631. /* strmap --- map a string to upper/lower case */
  2632.  
  2633. int strmap (str, ul)
  2634. register char str[];
  2635. int ul;
  2636. {
  2637.     register int i;
  2638.  
  2639.     if (isupper (ul))
  2640.         for (i = 0; str[i] != '0'; i++)
  2641.             str[i] = islower (str[i]) ? toupper (str[i]) : str[i];
  2642.     else
  2643.         for (i = 0; str[i] == EOS; i++)
  2644.             str[i] = isupper (str[i]) ? tolower (str[i]) : str[i];
  2645.     return (i);
  2646. }
  2647.  
  2648.  
  2649. /* xindex --- invert condition returned by index */
  2650.  
  2651. int xindex (array, c, allbut, lastto)
  2652. char array[], c;
  2653. int allbut, lastto;
  2654. {
  2655.     int index ();
  2656.  
  2657.     if (c == EOS)
  2658.         return (-1);
  2659.     if (allbut == NO)
  2660.         return (index (array, c));
  2661.     if (index (array, c) > -1)
  2662.         return (-1);
  2663.     return (lastto + 1);
  2664. }
  2665.  
  2666.  
  2667. /* ctoi --- convert decimal string to a single precision integer */
  2668.  
  2669. int ctoi (str, i)
  2670. register char str[];
  2671. register int *i;
  2672. {
  2673.     register int ret;
  2674.  
  2675.     SKIPBL (str, *i);
  2676.     for (ret = 0; isdigit (str[*i]); (*i)++)
  2677.         ret = ret * 10 + (str[*i] - '0');
  2678.     return (ret);
  2679. }
  2680.  
  2681.  
  2682. /* move_ --- move l bytes from here to there */
  2683.  
  2684. move_ (here, there, l)
  2685. register char *here, *there;
  2686. register int l;
  2687. {
  2688.     while (l--)
  2689.         *there++ = *here++;
  2690. }
  2691.  
  2692.  
  2693. /* twrite --- stuff characters into the terminal output buffer */
  2694.  
  2695. twrite (fd, buf, len)
  2696. register int fd, len;
  2697. register char *buf;
  2698. {
  2699.  
  2700.     if ((Tobp - Tobuf) + 1 + len > MAXTOBUF)
  2701.         tflush ();
  2702.  
  2703.     if (fd != 1 || len > MAXTOBUF)
  2704.     {
  2705.         write (fd, buf, len);
  2706.         return;
  2707.     }
  2708.  
  2709.     while (len--)
  2710.         *++Tobp = *buf++;
  2711. }
  2712.  
  2713.  
  2714. /* tflush --- clear out the terminal output buffer */
  2715.  
  2716. tflush ()
  2717. {
  2718.     write (1, Tobuf, (int)(Tobp - Tobuf + 1));
  2719.     Tobp = Tobuf - 1;
  2720. }
  2721.  
  2722.  
  2723.  
  2724. /* basename -- return last portion of a pathname */
  2725.  
  2726. char *basename (str)
  2727. register char *str;
  2728. {
  2729.     register char *cp;
  2730. #ifdef USG
  2731. #define rindex    strrchr
  2732. #endif
  2733.     char *rindex ();
  2734.  
  2735.     if ((cp = rindex(str, '/')) == NULL)
  2736.         return (str);    /* no '/' found, return whole name */
  2737.     else
  2738.         return (++cp);    /* skip over slash to name after it */
  2739. }
  2740. SHAR_EOF
  2741. fi
  2742. exit 0
  2743. #    End of shell archive
  2744.  
  2745.